import select, socket

send_queue = {
}


def start_udp_server(address, port):
    server_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server_udp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_udp.bind((address, port))
    clients = []

    while True:

        data, addr = server_udp.recvfrom(65535)
        try:
            if addr not in clients:
                clients.append(addr)

            for r in clients:
                server_udp.sendto(data, r)

        except ConnectionError:
            clients.remove(addr)
            server_udp.close()


def start_tcp_poll_server(address, port):
    pass


def start_tcp_server(address, port):
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((address, port))
    server.listen(10)
    ready_read = [server]
    ready_white = []
    ready_except = []

    while True:
        _read_list, _write_list, _except_list = select.select(ready_read, ready_white, ready_except)
        for fd in _read_list:
            if fd == server:
                client, addr = server.accept()
                for r in ready_read:
                    if r != server:
                        if r not in send_queue:
                            send_queue[r] = []
                            data_queue = send_queue[r]
                            data_queue.append(('{}is online now'.format(addr).encode('utf-8')))
                        if r not in ready_white:
                            ready_white.append(r)
                ready_read.append(client)
            else:
                try:
                    data = fd.recv(65535)
                    if not data:
                        raise ConnectionError
                    else:
                        try:
                            print('{} sent a message:{}'.format(fd.getpeername(), data.decode("utf-8")))
                        except:
                            pass
                    for rr in ready_read:
                        if rr != fd and rr != server:
                            rr.send(data)
                except ConnectionError:
                    ready_read.remove(fd)
                    fd.close()

        for fd in _write_list:
            if fd not in send_queue:
                ready_white.remove(fd)
                continue

            data_queue = send_queue[fd]
            data = data_queue.pop(0)
            fd.send(data)
            if not data_queue:
                ready_white.remove(fd)
                del send_queue[fd]


import argparse
import sys

print(sys.argv)

ap = argparse.ArgumentParser()
ap.add_argument("-t", type=str, choices=("tcp", "udp"), help="to use tcp / udp", default="tcp")
ap.add_argument("-H", type=str, required=True, help="the ip address to bind")
ap.add_argument("-p", type=int, required=True, help="the port to bind")

arg = ap.parse_args(sys.argv[1:])
if arg.t == "tcp":
    start_tcp_server(arg.H, arg.p)
else:
    start_udp_server(arg.H, arg.p)
